Frontend Forever App
We have a mobile app for you to download and use. And you can unlock many features in the app.
Get it now
Intall Later
Run
HTML
CSS
Javascript
Output
Document
LIFE
@charset "UTF-8"; @import url(https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,600,700,800); *, :after, :before { box-sizing: border-box; padding: 0; margin: 0; } @import url('https://fonts.googleapis.com/css2?family=Cinzel+Decorative:wght@400;700;900&display=swap'); html, body { height: 100%; margin: 0; } body { background: black; display: grid; place-content: center; overflow-x: hidden; } img { position: fixed; width: 100%; height: 100%; object-fit: stretch; } h1 { margin: 0; font-size: 15vh; line-height: 1.2; max-width: 100%; font-family: "Cinzel Decorative"; text-align: center; color: white; opacity: 0; }
console.log("Event Fired") // Using VFX-JS. // https://amagi.dev/vfx-js import { VFX } from "https://esm.sh/@vfx-js/core"; import { getSDFImage } from "https://esm.sh/@fand/image-to-sdf"; const shader = ` precision highp float; uniform vec2 resolution; uniform vec2 mouse; uniform vec2 offset; uniform float time; uniform sampler2D src; #define PI 3.141593 float rand(vec2 p) { return fract(sin(dot(p, vec2(484., 398.)) * 984.)); } vec3 spectrum(float x) { return cos((x - vec3(0, .5, 1)) * vec3(.6, 1., .5) * PI); } float get(vec2 uv) { return texture2D(src, uv).r; } mat2 rot(float t) { float c = cos(t), s = sin(t); return mat2(c, -s, s, c); } // https://iquilezles.org/articles/smin float smin(float a, float b, float k) { float h = max(k-abs(a-b),0.0); return min(a, b) - h*h*0.25/k; } float sdText(vec3 p) { p.xy *= rot(sin(time * 0.5) * 0.2); p.xz *= rot(-time * 0.3); float dxy = get(clamp(p.xy * 0.5 + 0.5, 0., 1.)); float dz = abs(p.z); return length(vec2(dxy, dz)) - .1; } float sdParticles(vec3 p) { vec3 q = p; q.xz *= rot(time * 0.23); float r = .1 * (sin(p.x + p.z) + 1.1); q.y -= time; q += 2.3; q = mod(q, 5.) - 2.5; float d = length(q) - r; q = p; q.xy *= rot(.2); q.xz *= rot(time * 0.2 - p.y * 0.03); r = .08 * (sin(p.z - p.y) + 1.1); q.y -= time * .7; q += 3.7; q = mod(q, 7.2) - 3.6; d = min(d, length(q) - r); r = .08 * (sin(p.z - p.y) + 1.1); q = p; q.xz *= rot(time * 0.18 + p.y * 0.02); q.x += sin(q.y) * .4; q.y -= time * .6; q.y = mod(q.y, 3.) - 1.5; d = min(d, length(q) - r); q = p; q.xz *= rot(time * -0.03 + p.y * -0.01); q.x += sin(q.y * .7 + .8) * .6; q.y -= time * .5; q.y = mod(q.y, 4.) - 2.; d = min(d, length(q) - r); return d; } float map(vec3 p) { float d = sdText(p); d = smin(d, sdParticles(p), .4); return d; } vec3 getNormal(vec3 p) { vec2 d = vec2(0, 1); return normalize(vec3( map(p + d.yxx) - map(p - d.yxx), map(p + d.xyx) - map(p - d.xyx), map(p + d.xxy) - map(p - d.xxy) )); } void trace(vec2 uv, vec2 p) { vec3 ro = vec3(0, 0, 1.7); vec3 rd = normalize(vec3(p, -1)); vec3 rp; float t = 0.; float d = 0.; float c = 0.; float occ = 0.; for (int i = 0; i < 80; i++) { rp = ro + rd * t; d = map(rp); if (d < 0.003) { c = 1. - t * 0.06; occ = float(i) * 0.006 + (cos(rp.y * 2. - 1.) * .4 + .5) * -0.15; break; } t += d * 0.3; } gl_FragColor = mix( vec4(.95, .55, .7, 1), vec4(.4, .7, .83, 1) - occ + pow(dot(getNormal(rp), vec3(0, 1, 0)), 10.) * 0.6, clamp(c, 0., 1.) ); float l = length(uv - .5); gl_FragColor.rgb *= 0.7 + spectrum(sin(l) * .5 + .5) * 0.5; gl_FragColor -= pow(l, 3.) * 0.5; gl_FragColor -= sin((uv.x - uv.y) * 1500. + time * 40.) * 0.02; // hatching } void main() { vec2 uv = (gl_FragCoord.xy - offset) / resolution; vec2 p = uv * 2. - 1.; p.x *= resolution.x / resolution.y; trace(uv, p); } `; // Constants const padding = 30; const lineHeight = 1.2; const leading = 0.17; const ratio = window.devicePixelRatio || 1; // Source element const e = document.querySelector('h1'); const vfx = new VFX({ pixelRatio: 0.5 }); (async () => { // Convert text to canvas const canvas = textToCanvas(); canvas.style.opacity = '0'; document.body.appendChild(canvas); // Create SDF const sdf = await getSDFImage(canvas, { width: canvas.width, height: canvas.height, spread: 100, padding: 100, pixelRatio: 2, }); sdf.style.opacity = '0'; document.body.appendChild(sdf); // Mouse event let mouse = [0, 0]; let mouseTarget = [0, 0]; window.addEventListener("mousemove", (e) => { mouseTarget = [ e.clientX / window.innerWidth * 2. - 1, -(e.clientY / window.innerHeight * 2 - 1), ]; }); // Init vfx.add(sdf, { shader }); })(); function textToCanvas() { const canvas = document.createElement('canvas'); const ctx = canvas.getContext("2d"); // Dimensions const rect = e.getBoundingClientRect(); canvas.style.position = "fixed"; canvas.style.left = `${rect.left - padding}px`; canvas.style.top = `${rect.top - padding}px`; canvas.style.width = `${rect.width + padding * 2}px`; canvas.style.height = `${rect.height + padding * 2}px`; canvas.width = (rect.width + padding * 2) * ratio; canvas.height = (rect.height + padding * 2) * ratio; canvas.style.pointerEvents = "none"; // Sync text styles const styles = window.getComputedStyle(e); const fontSize = parseFloat(styles.fontSize); const halfLeading = fontSize * leading; ctx.scale(ratio, ratio); ctx.clearRect(0, 0, rect.width, rect.height); ctx.font = styles.font; ctx.fillStyle = "rgba(0, 0, 0, 1)"; ctx.fillStyle = "white"; ctx.textBaseline = "top"; ctx.textAlign = "center"; // Draw lines const lines = e.innerText.split('\n'); let yOffset = 0; for (const line of lines) { ctx.fillText(line, padding + rect.width * 0.5, padding + halfLeading + yOffset); yOffset += fontSize * lineHeight; } return canvas; }